package com.xunwulian.cmpp.pdu;

import com.xunwulian.base.constant.ConstantBean;
import com.xunwulian.cmpp.sms.ByteBuffer;
import com.xunwulian.cmpp.sms.NotEnoughDataInByteBufferException;
import com.xunwulian.cmpp.sms.PDUException;
import com.xunwulian.cmpp.util.CmppConstant;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Connect extends Request implements Serializable {

    private static final long serialVersionUID = -2208862469803452963L;
    private String clientId = ConstantBean.ZXTD_CMPP_SERVER_CLIENTID;
    private byte[] authClient = new byte[16];
    private byte version = (byte) 0x00;
    private String sharedSecret = ConstantBean.ZXTD_CMPP_SERVER_PASSWROD;

    public Connect() {
        super(CmppConstant.CMD_CONNECT);
    }

    public Connect(String clientId, String sharedSecret) {
        super(CmppConstant.CMD_CONNECT);

        this.clientId = clientId;
        this.sharedSecret = sharedSecret;

        // 协议版本号
        setVersion(CmppConstant.PROTOCALTYPE_VERSION_CMPP3);

		/*
         * 权限验证，MD5（Source_Addr+9 字节的0 +shared secret+timestamp）
		 */
        setAuthClient(genAuthClient());

        setTimeStamp(genTimeStamp());
    }

    public void setBody(ByteBuffer buffer) throws PDUException {
        try {
            setClientId(buffer.removeStringEx(6));
            setAuthClient(buffer.removeBytes(16).getBuffer());
            setVersion(buffer.removeByte());
            setTimeStamp(buffer.removeInt());
        } catch (NotEnoughDataInByteBufferException e) {
            e.printStackTrace();
            throw new PDUException(e);
        }
    }

    public ByteBuffer getBody() {
        ByteBuffer buffer = new ByteBuffer();
        buffer.appendString(getClientId(), 6);
        buffer.appendBytes(getAuthClient(), 16);
        buffer.appendByte(getVersion());
        buffer.appendInt(getTimeStamp());
        return buffer;
    }

    public byte[] genAuthClient() {
        /*
        byte[] result = new byte[16];
		try {
			ByteBuffer buffer = new ByteBuffer();
			buffer.appendString(clientId, clientId.length());
			
			byte[] ba = new byte[9];
			for(int i = 0; i< 9; i++){
				ba[i] = 0;
			}
			buffer.appendBytes(ba);
			
			buffer.appendString(sharedSecret, sharedSecret.length());

			Date date = new Date();
			Format formatter = new SimpleDateFormat("MMddHHmmss");
			
			String stimeStamp = formatter.format(date);
			logger.error("stimeStamp: " +stimeStamp);
			
			buffer.appendInt(Integer.valueOf(stimeStamp));
			
			MessageDigest md = MessageDigest.getInstance("MD5");
			result = md.digest(buffer.getBuffer());
		} catch (Exception ex) {
			logger.error("Failed genAuthClient!");
		}
		return result;
		*/
        SimpleDateFormat formatter = new SimpleDateFormat("MMddHHmmss");
        String time = formatter.format(new Date());
        this.setTimeStamp(Integer.parseInt(time));
        try {
            authClient = MessageDigest.getInstance("MD5").digest(
                    (clientId + "\0\0\0\0\0\0\0\0\0" + sharedSecret + time).getBytes());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return authClient;
    }

    public static byte[] intToByteArray(int a) {
        return new byte[]{
                (byte) ((a >> 24) & 0xFF),
                (byte) ((a >> 16) & 0xFF),
                (byte) ((a >> 8) & 0xFF),
                (byte) (a & 0xFF)
        };
    }

    public static String getHexDump(byte[] data) {
        String dump = "";
        try {
            int dataLen = data.length;
            for (int i = 0; i < dataLen; i++) {
                dump += Character.forDigit((data[i] >> 4) & 0x0f, 16);
                dump += Character.forDigit(data[i] & 0x0f, 16);
            }
        } catch (Throwable t) {
            // catch everything as this is for debug
            dump = "Throwable caught when dumping = " + t;
        }
        return dump;
    }

    public String byteBufferToString() {
        String result = "";
        StringBuffer stringBuffer = new StringBuffer();

        byte[] byteArray = this.getData().getBuffer();
        byte[] tmp = new byte[4];
        for (int i = 0; i < 4; i++) {
            tmp[i] = byteArray[i];
        }
        stringBuffer.append(String.format("%04d", byteArrayToInt(tmp)));

        for (int i = 0; i < 4; i++) {
            tmp[i] = byteArray[4 + i];
        }
        stringBuffer.append(String.format("%04d", byteArrayToInt(tmp)));

        for (int i = 0; i < 4; i++) {
            tmp[i] = byteArray[8 + i];
        }
        stringBuffer.append(String.format("%04d", byteArrayToInt(tmp)));

        result = stringBuffer.toString();
        ByteBuffer bf = this.getBody();
        try {
            result = result.concat(bf.removeStringEx(6));
            result = result.concat(bf.removeStringEx(16));

            byte ver = bf.removeByte();
            int high = ver & 0xF0;
            int low = ver & 0x0F;

            result = result.concat(String.format("%d", high));
            result = result.concat(String.format("%d", low));

            result = result.concat(String.format("%d", bf.removeInt()));

        } catch (NotEnoughDataInByteBufferException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        return result;
    }

    public static int byteArrayToInt(byte[] bytes) {
        int value = 0;
        // 由高位到低位
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (bytes[i] & 0x000000FF) << shift;// 往高位游
        }
        return value;
    }

    public int genTimeStamp() {
        Date date = new Date();
        Format formatter = new SimpleDateFormat("MMddHHmmss");
        int timeStamp = Integer.valueOf(formatter.format(date));
        return timeStamp;
    }

    public byte[] getAuthClient() {
        return authClient;
    }

    public void setAuthClient(byte[] authClient) {
        this.authClient = authClient;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public int getTimeStamp() {
        return timeStamp;
    }

    public void setTimeStamp(int timeStamp) {
        this.timeStamp = timeStamp;
    }

    public byte getVersion() {
        return version;
    }

    public void setVersion(byte version) {
        this.version = version;
    }

    public String getSharedSecret() {
        return sharedSecret;
    }

    public void setSharedSecret(String sharedSecret) {
        this.sharedSecret = sharedSecret;
    }

    protected Response createResponse() {
        return new ConnectResp();
    }

    public boolean isTransmitter() {
        return (version == (byte) 0x18);
    }

    public boolean isReceiver() {
        return (version == (byte) 0x01);
    }

    public void setData(ByteBuffer buffer) throws PDUException {
        header.setData(buffer);
        setBody(buffer);
    }

    public ByteBuffer getData() {
        ByteBuffer bodyBuf = getBody();
        header.setCommandLength(CmppConstant.PDU_HEADER_SIZE + bodyBuf.length());
        ByteBuffer buffer = header.getData();
        buffer.appendBuffer(bodyBuf);
        return buffer;
    }

    public String name() {
        return "CMPP Connect";
    }

    public ConnectResp getResponse() {
        ConnectResp conResp = (ConnectResp) createResponse();
        conResp.setSequenceNumber(getSequenceNumber());
        conResp.setCommandId(CmppConstant.CMD_CONNECT_RESP);
        return conResp;
    }

    @Override
    public String dump() {
        return super.dump();
    }
}
